package org.feng.service.impl;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.sun.istack.NotNull;
import org.feng.pojo.BaseEntity;
import org.feng.entity.pojo.Datasource;
import org.feng.entity.pojo.Generate;
import org.feng.serive.BaseService;
import org.feng.serive.impl.BaseServiceImpl;
import org.feng.serive.impl.BaseServiceImplNoExtendsImpl;
import org.feng.service.DatasourceService;
import org.feng.utils.NamingUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Component
public class GenerateAuto {
    @Autowired
    private DatasourceService datasourceService;
    private static final String AUTHOR = "feng";
    private static final String ENTITY = "entity";
    private static final String CONTROLLER = "controller";
    private static final String SERVICE = "org/feng/service";
    private static final String SERVICE_IMPL = "service.impl";
    private static final String MAPPER = "mapper";
    private static final String XML = "mapper";
    private static final String CONTROLLER_PATH = "templates/controller.java";
    private static final String MAPPER_PATH = "templates/mapper.java";
    private static final String SERVICE_PATH = "templates/service.java";
    private static final String ENTITY_PATH = "templates/entity.java";
    private static final String SERVICE_IMPL_PATH = "templates/serviceImpl.java";
    private static final String MAPPER_XML_PATH = "templates/mapper.xml";

    public void execute(Generate generate) {
        Datasource datasource = datasourceService.getById(generate.getDatasourceId());
        Map<String, Object> map = new HashMap<>(1);
        map.put("auth", NamingUtil.lineToHump(generate.getTableName().replace(generate.getTablePrefix(), "")));
        map.put("entity", generate.getTableName().replace(generate.getTablePrefix(), ""));
        FastAutoGenerator.create(datasource.getUrl(), datasource.getUsername(), datasource.getPassword())
                .globalConfig(builder -> {
                    builder.author(AUTHOR)
                            .outputDir(generate.getJavaFile())
                            .fileOverride()
                            .enableSwagger()
                            .disableOpenDir()
                            .dateType(DateType.TIME_PACK);
                })
                .packageConfig(builder -> {
                    builder.parent(generate.getParentPath())
                            .moduleName(generate.getModule())
                            .entity(ENTITY)
                            .service(SERVICE)
                            .serviceImpl(SERVICE_IMPL)
                            .mapper(MAPPER)
                            .xml(XML)
                            .controller(CONTROLLER);
                })
                .templateConfig(builder -> {
                    builder.disable(TemplateType.ENTITY, TemplateType.SERVICE, TemplateType.SERVICEIMPL, TemplateType.CONTROLLER, TemplateType.MAPPER, TemplateType.XML)
                            .entity(ENTITY_PATH)
                            .service(SERVICE_PATH)
                            .serviceImpl(SERVICE_IMPL_PATH)
                            .mapper(MAPPER_PATH)
                            .controller(CONTROLLER_PATH)
                            .mapperXml(MAPPER_XML_PATH);
                })
                .injectionConfig(builder -> {
                    builder.customMap(map)
                            .customFile(getInjectionNameAndPath(generate))
                            .beforeOutputFile((tableInfo, objectMap) -> {
                                TableInfo table = (TableInfo) objectMap.get("table");
                                table.setEntityName(table.getEntityName().replace("Entity", ""));
                                objectMap.put("table", table);
                            });
                })
                .strategyConfig(builder -> {
                    builder.enableSkipView()
                            .enableCapitalMode()
                            .addInclude(generate.getTableName())
                            .addTablePrefix(generate.getTablePrefix())
                            //实体配置
                            .entityBuilder().superClass(BaseEntity.class)
                            .enableLombok()
                            .enableTableFieldAnnotation()
                            .versionColumnName("version")
                            .versionPropertyName("version")
                            .logicDeleteColumnName("is_deleted")
                            .logicDeletePropertyName("isDeleted")
                            .naming(NamingStrategy.underline_to_camel)
                            .columnNaming(NamingStrategy.underline_to_camel)
                            .addSuperEntityColumns("create_id", "create_dept", "update_id", "create_time", "update_time", "is_deleted")
                            .idType(IdType.ASSIGN_ID)
                            .formatFileName("%sEntity")
                            //controller配置
                            .controllerBuilder().enableRestStyle().formatFileName("%sController")
                            .serviceBuilder()
                            .superServiceClass(BaseService.class)
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImpl")
                            .mapperBuilder()
                            .superClass(BaseMapper.class)
                            .enableMapperAnnotation()
                            .enableBaseResultMap()
                            .formatMapperFileName("%sMapper")
                            .formatXmlFileName("%sMapper");
                    if (generate.getIsParent() == 1) {
                        builder.serviceBuilder().superServiceImplClass(BaseServiceImplNoExtendsImpl.class);
                    } else {
                        builder.serviceBuilder().superServiceImplClass(BaseServiceImpl.class);
                    }

                }).templateEngine(new VelocityTemplateEngine() {
                    //重写自定义模板 保存路径
                    @Override
                    protected void outputCustomFile(@NotNull Map<String, String> customFile, @NotNull TableInfo tableInfo, @NotNull Map<String, Object> objectMap) {
                        String packagePath = generate.getParentPath().replace(".", File.separator) + File.separator + generate.getModule();
                        customFile.forEach((key, value) -> {
                            StringBuilder fileName = new StringBuilder();
                            fileName.append(generate.getJavaFile()).append(File.separator);
                            if (value.contains("vo")) {
                                fileName.append(packagePath).append(File.separator).append("vo").append(File.separator).append(key);
                            }
                            if (value.contains("vue")) {
                                fileName.append("vue").append(File.separator).append(key);
                            }
                            if (value.contains("js")) {
                                fileName.append("js").append(File.separator).append(key);
                            }
                            outputFile(new File(fileName.toString()), objectMap, value);
                        });
                        ;
                    }
                }).execute();
    }

    /**
     * 获取自定义模板名称和路径
     *
     * @param generate
     * @return
     */
    private Map<String, String> getInjectionNameAndPath(Generate generate) {
        HashMap<String, String> map = new HashMap<>(3);
        String fileName = generate.getTableName().replace(generate.getTablePrefix(), "");
        map.put(NamingUtil.lineToHump(fileName) + ".vue", "/templates/vue.vue.vm");
        map.put(NamingUtil.lineToHump(fileName) + ".js", "/templates/api.js.vm");
        String voName = NamingUtil.lineToHump(fileName);
        voName = voName.substring(0, 1).toUpperCase(Locale.ROOT) + voName.substring(1);
        map.put(voName + "VO.java", "/templates/vo.java.vm");
        return map;
    }
}
